﻿using System;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.IO;

internal static class EncryptionHelper
{
    private static string passcode = "d.";
    private static string saltkey = "sd122231";
    public static Object EncryptObject(object obj)
    {

        byte[] key = EncryptionHelper.GetHashKey(passcode, saltkey);
        Type t = obj.GetType();

        PropertyInfo[] fi = t.GetProperties();

        object o = null;
        foreach (PropertyInfo f in fi)
        {

            if (f.PropertyType == typeof(string))
            {
                PropertyInfo pi = t.GetProperty(f.Name, BindingFlags.Public | BindingFlags.Instance);

                try
                {
                    o = pi.GetValue(obj, null);
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.ToString());
                }

                string s = (string)o;
                f.SetValue(obj, EncryptionHelper.Encrypt(key, s), null);
            }

        }

        return obj;
    }

    public static Object DecryptObject(object obj)
    {
        byte[] key = EncryptionHelper.GetHashKey(passcode, saltkey);
        Type t = obj.GetType();
        PropertyInfo[] fi = t.GetProperties();
        object o = null;
        foreach (PropertyInfo f in fi)
        {
            if (f.PropertyType == typeof(string))
            {
                PropertyInfo pi = t.GetProperty(f.Name, BindingFlags.Public | BindingFlags.Instance);

                try
                {
                    o = pi.GetValue(obj, null);
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.ToString());
                }

                string s = (string)o;
                f.SetValue(obj, EncryptionHelper.Decrypt(key, s), null);
            }
        }
        return obj;
    }

    public static string EncryptString(string obj)
    {

        byte[] key = EncryptionHelper.GetHashKey(passcode, saltkey);

        return EncryptionHelper.Encrypt(key, obj);
    }

    public static string DecryptString(string obj)
    {
        byte[] key = EncryptionHelper.GetHashKey(passcode, saltkey);

        return EncryptionHelper.Decrypt(key, obj);
    }

    internal static byte[] GetHashKey(string hashKey, string salt)
    {
        UTF8Encoding encoder = new UTF8Encoding();
        byte[] saltBytes = encoder.GetBytes(salt);

        Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(hashKey, saltBytes);

        // Return the key
        return rfc.GetBytes(16);
    }

    internal static string Encrypt(byte[] key, string dataToEncrypt)
    {
        AesManaged encryptor = new AesManaged();

        // Set key and IV
        encryptor.Key = key;
        encryptor.IV = key;

        // create memory stream
        using (MemoryStream encryptionStream = new MemoryStream())
        {
            // Create crypto stream
            using (CryptoStream encrypt = new CryptoStream(encryptionStream, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
            {
                // Encrypt
                byte[] data = UTF8Encoding.UTF8.GetBytes(dataToEncrypt);
                encrypt.Write(data, 0, data.Length);
                encrypt.FlushFinalBlock();
                encrypt.Close();

                // Return encrypted data as base64 string
                return Convert.ToBase64String(encryptionStream.ToArray());
            }
        }
    }

    internal static string Decrypt(byte[] key, string encryptedString)
    {
        AesManaged decryptor = new AesManaged();

        // convert base64 string to byte array
        byte[] encryptedData = Convert.FromBase64String(encryptedString);

        // Set key and IV
        decryptor.Key = key;
        decryptor.IV = key;

        // create  memory stream
        using (MemoryStream decryptionStream = new MemoryStream())
        {
            // Create crypto stream
            using (CryptoStream decrypt = new CryptoStream(decryptionStream, decryptor.CreateDecryptor(), CryptoStreamMode.Write))
            {
                // Encrypt
                decrypt.Write(encryptedData, 0, encryptedData.Length);
                decrypt.Flush();
                decrypt.Close();

                // Return unencrypted data
                byte[] decryptedData = decryptionStream.ToArray();
                return UTF8Encoding.UTF8.GetString(decryptedData, 0, decryptedData.Length);
            }
        }
    }

    public static string EncryptMD5(string toEncrypt)
    {
        byte[] keyArray;
        byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

        string key = "x";
        //System.Windows.Forms.MessageBox.Show(key);
        //If hashing use get hashcode regards to your key
        MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
        keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
        //Always release the resources and flush data
        // of the Cryptographic service provide. Best Practice

        hashmd5.Clear();

        TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
        //set the secret key for the tripleDES algorithm
        tdes.Key = keyArray;
        //mode of operation. there are other 4 modes.
        //We choose ECB(Electronic code Book)
        tdes.Mode = CipherMode.ECB;
        //padding mode(if any extra byte added)

        tdes.Padding = PaddingMode.PKCS7;

        ICryptoTransform cTransform = tdes.CreateEncryptor();
        //transform the specified region of bytes array to resultArray
        byte[] resultArray =
          cTransform.TransformFinalBlock(toEncryptArray, 0,
          toEncryptArray.Length);
        //Release resources held by TripleDes Encryptor
        tdes.Clear();
        //Return the encrypted data into unreadable string format
        return Convert.ToBase64String(resultArray, 0, resultArray.Length);
    }

    public static string DecryptMD5(string cipherString)
    {
        byte[] keyArray;
        //get the byte code of the string

        byte[] toEncryptArray = Convert.FromBase64String(cipherString);


        //Get your key from config file to open the lock!
        string key = "x2";


        //if hashing was used get the hash code with regards to your key
        MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
        keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
        //release any resource held by the MD5CryptoServiceProvider

        hashmd5.Clear();


        TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
        //set the secret key for the tripleDES algorithm
        tdes.Key = keyArray;
        //mode of operation. there are other 4 modes. 
        //We choose ECB(Electronic code Book)

        tdes.Mode = CipherMode.ECB;
        //padding mode(if any extra byte added)
        tdes.Padding = PaddingMode.PKCS7;

        ICryptoTransform cTransform = tdes.CreateDecryptor();
        byte[] resultArray = cTransform.TransformFinalBlock(
                             toEncryptArray, 0, toEncryptArray.Length);
        //Release resources held by TripleDes Encryptor                
        tdes.Clear();
        //return the Clear decrypted TEXT
        return UTF8Encoding.UTF8.GetString(resultArray);
    }

}
